#pragma once

#include <iostream>
#include <string>
#include "Log.hpp"
#include "Com.hpp"
#include <jsoncpp/json/json.h>
#include "InetAddr.hpp"
#include "Socket.hpp"

const static std::string sep = "/r/n";

class Request
{
    public:
    Request(int x , int y , char oper)
        :_x(x)
        ,_y(y)
        ,_oper(oper)
    {
    }
    Request()
    {

    }
    ~Request()
    {
    }
    std::string  Serialize()
    {
        Json::Value root;
        root["X"] = _x;
        root["Y"] = _y;
        root["Oper"] = _oper;


        Json::FastWriter writer;
        std::string json_str = writer.write(root);
        return json_str;
    }

    bool Deserialize(std::string in)
    {
        Json::Value root;
        Json::Reader reader;
        bool ret = reader.parse(in , root);
        if(ret)
        {
            _x = root["X"].asInt();
            _y = root["Y"].asInt();
            _oper = root["Oper"].asInt();
        }
        return ret;
    }

    void SetX(int x)
    {
        _x = x;
    }
    void SetY(int y)
    {
        _y = y;
    }
    void SetOper(char oper)
    {
        _oper = oper;
    }
    char GetOper()
    {
        return _oper;
    }
    int GetX()
    {
        return _x;
    }
    int GetY()
    {
        return _y;
    }
    private:
    int _x;
    int _y;
    char _oper;
};

class Response
{
    public:
    Response(int result ,int code)
        :_result(result)
        ,_code(code)
    {

    }
    Response()
    {

    }
    ~Response()
    {

    }

    std::string Serialize()
    {
        Json::Value root;
        root["Result"] = _result;
        root["Code"] = _code;


        Json::FastWriter writer;
        std::string json_str = writer.write(root);
        return json_str;
    }

    bool Deserialize(std::string in)
    {
        Json::Value root;
        Json::Reader reader;
        bool ret = reader.parse(in , root);
        if(ret)
        {
            _result = root["Result"].asInt();
            _code = root["Code"].asInt();
        }
        return ret;
    }
    void SetResult(int result)
    {
        _result = result;
    }
    void SetCode(int code)
    {
        _code = code;
    }
    void ShowResult()
    {
        std::cout << _result <<"[" << _code << "]";
    }
    private:
    int _result;
    int _code;
}; 

using func_t = std::function<Response (Request&)>;

class Protocol
{
    public:
    Protocol()
    {

    }
    Protocol(func_t service)
        :_service(service)
    {

    }
    ~Protocol()
    {

    }

    std::string Encode(std::string& json_str)
    {
        std::string json_len_str = std::to_string(json_str.size());
        std::string package = json_len_str + sep + json_str + sep;

        return package;
    }

    bool Decode(std::string& str , std::string* package)
    {
        auto pos = str.find(sep);
        if(std::string::npos == pos)
        {
            //字符串中连报头都没有
            return false;
        }
        //字符串中至少有报头可以提取继续判断
        std::string package_len_str = str.substr(0 , pos);//报文的报头
        size_t json_len_int = std::stoi(package_len_str);//json串应该的长度

        size_t str_len = str.size();//传入的字符串的长度
        //50/r/n{json_str}/r/n
        size_t package_len_int = package_len_str.size() + 2*sep.size() + json_len_int;//报文的长度
        if(str_len < package_len_int)
        {
            return false;
        }
        //到这里字符串至少有一个完整的报文
        *package = str.substr(pos  + sep.size() , json_len_int);
        str.erase(0 , package_len_int );
        return true;
    }

    void GetRequest(std::shared_ptr<Socket> sock , InetAddr client)
    {
        std::string bufferqueue;
        while(true)
        {
            int n = sock->Recv(&bufferqueue);
            std::cout <<"Recv" <<std::endl;
            if(n > 0)
            {
                std::string package;
                while(Decode(bufferqueue , &package))
                {
                    //有完整的json串
                    //反序列化

                    Request req;
                    bool ret = req.Deserialize(package);
                    if(!ret)
                    {
                        LOG(LogLevel::ERROR) << "Request Deserialize failed ,IP:" << client.GetIP();
                        continue;
                    }
                    LOG(LogLevel::ERROR) << "Request Deserialize success";
                    //拿到json串调用上层处理
                    Response  res;
                    res = _service(req);
                    //上层处理完应该序列化
                    std::string json_str = res.Serialize();
                    //序列化完成之后应该去添加报头
                    std::string send_message = Encode(json_str);
                    //发送报文
                    std::cout << "走到了server send的地方" <<std::endl;
                    int send_t = sock->Send(send_message);
                    if(send_t < 0)
                    {
                        LOG(LogLevel::ERROR) << "send " << client.GetIP() << "failed";
                    }
                    else{
                        LOG(LogLevel::DEBUG) << "send " << client.GetIP() << "success";

                    }
                }
            }
            else if(0 == n)
            {
                LOG(LogLevel::DEBUG) << "client quit" ;
                break;
            }
            else
            {
                LOG(LogLevel::ERROR) << "server recv error";
                break;
            }
        }
    }

    bool GetResponse(std::string& str , std::shared_ptr<Socket>& sock, Response& res)
    {
        while(true)
        {
           int n = sock->Recv(&str);
           if(n > 0 )
           {
                std::string package;
                while(Decode(str , &package))
                {
                 
                    res.Deserialize(package);

                    
                }
                return true;
           }
           else if(0 == n)
           {
                LOG(LogLevel::DEBUG) << "server quit";
                break;
                
           }
           else
           {
                LOG(LogLevel::ERROR) << "client recv error";
                break;
           }
        }
        return false;
    }

    std::string BuildRequestMethod(int x , int y , char oper)
    {
        Request req;
        req.SetX(x);
        req.SetY(y);
        req.SetOper(oper);
        std::string json_str = req.Serialize();
        return Encode(json_str);
    }
    private:
    func_t _service;
};